import { Component, OnInit, AfterViewInit, Input, ElementRef, Renderer2 } from '@angular/core';

import { Store } from '@ngrx/store';
import { LayoutSiderState, getLayoutSiderIsCollapsedSelector } from '../../../store';
import { OlState, layerSelector } from '../../store';
import * as fromMapSelector from '../../store/selectors/map.selector';
import { 
  MapState, 
  basemapsSelector, 
  SetBasemaps, 
  dataTableSelector
} from '../../../map/store';
import { Basemap, Resource } from '../../../map/models';

import Map from 'ol/map';
import Control from 'ol/control/control';
import { LayerAbstract } from '../../../map/components';

import { CustomLayer } from '../../../map/models';
import { MapCursorTypes } from '../../enums';

@Component({
  selector: 'ngx-ol-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit, AfterViewInit {

  public instance: Map;

  @Input() width: string = '100%';
  @Input() height: string = '100%';
  @Input() pixelRatio: number;
  @Input() keyboardEventTarget: Element | string;
  @Input() loadTilesWhileAnimating: boolean = false;
  @Input() loadTilesWhileInteracting: boolean = false;
  @Input() logo: string | boolean;
  @Input() moveTolerance: number = 1;
  @Input() renderer: 'canvas' | 'webgl';

  controls: Control[] = [];
  updateSizeTimer: any;
  basemap: any;

  constructor(
    private host: ElementRef,
    private store: Store<OlState>,
    private LayoutSiderStore: Store<LayoutSiderState>,
    private mapStore: Store<MapState>,
    private rendererElement: Renderer2
  ) { }

  ngOnInit() {
    this.initialInstance(this.host.nativeElement.firstElementChild);
  }

  ngAfterViewInit(): void {
    this.updateSize(100);
  }

  initialInstance(target: any): void {
    this.instance = new Map({
      pixelRatio: this.pixelRatio,
      keyboardEventTarget: this.keyboardEventTarget,
      loadTilesWhileAnimating: this.loadTilesWhileAnimating,
      loadTilesWhileInteracting: this.loadTilesWhileInteracting,
      logo: this.logo,
      moveTolerance: this.moveTolerance,
      renderer: this.renderer,
      controls: this.controls
    });
    this.instance.setTarget(target);
    this.LayoutSiderStore.select(getLayoutSiderIsCollapsedSelector).subscribe((isCollapsed: boolean) => {
      this.updateSize(300);
    });
    this.mapStore.select(basemapsSelector.getCheckedBasemaps).subscribe((basemap: Basemap) => {
      basemap && this.setBasemap(basemap);
    });
    this.mapStore.select(fromMapSelector.getMapCursor).subscribe((cursor: MapCursorTypes) => this.setCursor(cursor));
  }

  addLayer(layer: any): void {
    this.instance.addLayer(layer);
  }

  removeLayer(layer: any): void {
    this.instance.removeLayer(layer);
  }

  addInteraction(interaction: any): void {
    this.instance.addInteraction(interaction);
  }

  removeInteraction(interaction: any): void {
    this.instance.removeInteraction(interaction);
  }

  updateSize(time: number): void {
    let current: number = 0;
    if(this.updateSizeTimer) {
      this.clearUpdateSizeTimer();
    }
    this.updateSizeTimer = setInterval(() => {
      this.instance.updateSize();
      current+=5;
      if(current > time) {
        this.clearUpdateSizeTimer();
      }
    }, 5);
  }

  clearUpdateSizeTimer(): void {
    clearInterval(this.updateSizeTimer);
    this.updateSizeTimer = undefined;
  }

  setBasemap(basemap: Basemap): void {
    if(this.basemap) this.instance.removeLayer(this.basemap);
    this.basemap = basemap.init();
    this.instance.addLayer(this.basemap);
  }

  private setCursor(cursor: MapCursorTypes): void {
    if(this.instance) {
      const target = this.instance.getTarget();
      this.rendererElement.setStyle(target, 'cursor', cursor);
    }
  }

}
